extends PlayerMoveComponentBase
class_name PlayerFlatMoveInCurveComponent
##若需要真实加减速时间严格等于设置时间，需要加速曲线或者减速曲线在结尾处刚好达到最高点或者最低点。

@export_group("加速")
@export var time_faster:float = 1
@export var curve_faster:Curve
var faster_progress:float = 0:
	set(value):
		faster_progress = clamp(value,0,1)

@export_group("减速")
@export var time_slower:float = 1
@export var curve_slower:Curve
var slower_progress:float = 0:
	set(value):
		slower_progress = clamp(value,0,1)

@export_group("转弯")
@export var curve_turn:Curve
@export var velocity_change_speed_turn:float = 1
@export var strength_turn:float = 0.1

var turn_progress:float = 0:
	set(value):
		turn_progress = clamp(value,0,1)

var current_state:Callable = idle

func _move(delta: float):
	update_state()
	current_state.call(delta)

#region update_state状态更新
func update_state():
	var have_input:bool = (input_dir != Vector2.ZERO)
	if !have_input:
		_update_state_when_have_not_input()
	else:
		_update_state_when_have_input()

func _update_state_when_have_not_input():
	var is_moving:bool = (mover.velocity != Vector2.ZERO)
	if is_moving:
		##当有速度但无输入时，即单位做沿速度方向做直线减速
		if current_state == deceleration:
			return
		current_state = deceleration
	else:
		if current_state == idle:
			return
		current_state = idle

func _update_state_when_have_input():
	var is_moving:bool = (mover.velocity != Vector2.ZERO)
	var angle = mover.velocity.angle_to(input_dir)
	var is_move_in_input_dir:bool = (angle <= PI / 18 and angle >= - PI / 18)
	
	if !is_moving:
		##当无速度但存在输入时，即单位做速度从零开始的加速运动。这只持续一帧，但我们不能缺少这一判断。
		if current_state == accelerate:
			return
		current_state = accelerate
	elif input_dir == - mover.velocity.normalized():
		##当输入方向与速度方向相反时，即单位做逆向加速运动时
		##额外判断是否能够原地逆向加速，如果不行进入转弯状态
		if current_state == accelerate and !is_input_changed:
			return
		current_state = deceleration
	elif is_move_in_input_dir:
		##当输入方向与速度方向大致一致时，即单位做直线加速或匀速运动
		if current_state == accelerate:
			return
		current_state = accelerate
	elif !is_move_in_input_dir:
		##当输入方向与速度方向有偏差时，即单位做转向运动
		if current_state == turn and !is_input_changed:
			return
		current_state = turn
#endregion

#region 移动
@warning_ignore("unused_parameter")
func idle(delta:float):
	pass

func accelerate(delta:float):
	add_faster_progress(delta)
	faster_progress += delta / time_faster
	var curve_value = curve_faster.sample(faster_progress)
	mover.velocity = max_speed * curve_value * input_dir

func deceleration(delta:float):
	add_slower_progress(delta)
	var curve_value = curve_slower.sample(slower_progress)
	var mover_velocity_dir:Vector2 = mover.velocity.normalized()
	if input_dir == Vector2.ZERO:
		mover.velocity = max_speed * curve_value * mover_velocity_dir
	else:
		mover.velocity = max_speed * curve_value * mover_velocity_dir.lerp(input_dir,slower_progress)

func turn(delta:float):
	if is_input_changed:
		turn_progress = 0
	add_turn_progress(delta)
	var mover_velocity_dir:Vector2 = mover.velocity.normalized()
	var curve_value = curve_turn.sample(turn_progress)
	mover.velocity = max_speed * curve_value * mover_velocity_dir.lerp(input_dir,strength_turn)
#endregion

#region 进度相关
func add_faster_progress(delta:float):
	faster_progress += delta / time_faster
	slower_progress -= delta / time_slower

func add_slower_progress(delta:float):
	faster_progress -= delta / time_faster
	slower_progress += delta / time_slower

func add_turn_progress(delta:float):
	slower_progress -= delta / time_slower
	turn_progress += delta / velocity_change_speed_turn
#endregion
